package com.pcbly.web.components.license;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.pcbly.web.OfficeHome;
import com.pcbly.web.components.utils.property.OfficeGlobals;

public class OfficeLicenseManager extends LicenseManager {

	private static Map<String, String> propertyDisplayNames = new HashMap<String, String>();
	private static final Log log = LogFactory
			.getLog(OfficeLicenseManager.class);
	private static OfficeLicenseManager instance;
	private boolean initialized;
	private boolean failed;

	static {
		propertyDisplayNames.put(
				OfficeLicenseProperty.numClusterMembers.name(),
				"Number of Cluster Members");
		propertyDisplayNames.put(OfficeLicenseProperty.numCopies.name(),
				"Number of Copies");
		propertyDisplayNames.put(OfficeLicenseProperty.numSeats.name(),
				"Number of Seats");
	}

	public static enum OfficeLicenseProperty {
		numSeats, numClusterMembers, numCopies, expirationDate;
	}

	private OfficeLicenseManager() {
		initialized = false;
		failed = false;
	}

	private void init() {

		if (!initialized) {
			File file = OfficeHome.getLicenseFile();
			if (!file.canRead() && file.exists()) {
				String msg = (new StringBuilder())
						.append("The \"")
						.append(file.getName())
						.append("\" license file was found")
						.append(
								", but Jive does not have permission to read it.")
						.toString();
				log.fatal(msg);
				throw new LicenseException(msg);
			}
			if (!file.exists() && !OfficeGlobals.isEvalBuild()) {
				String msg = (new StringBuilder()).append("The \"").append(
						file.getName()).append(
						"\" license file was not found, ").append(
						"evaluation mode will be used").toString();
				log.fatal(msg);
			}
			try {
				Reader reader = null;
				if (file.exists())
					reader = new BufferedReader(new FileReader(file));
				initialize(reader);
			} catch (IOException e) {
				log.debug(e.getMessage(), e);
				failed = true;
				throw new LicenseException("Reading of license failed.");
			} catch (LicenseException e) {
				log.debug(e.getMessage(), e);
				failed = true;
				throw e;
			} finally {
				initialized = true;
			}
			initialized = true;
		} else {
			log.debug("Already initialized, call destroy()");
		}
	}

	public void initialize(Reader reader) throws IOException {
		if (!initialized)
			initialize(((LicenseProvider) (new DefaultLicenseProvider())),
					reader);
		else
			log.debug("Already initialized, call destroy");
	}

	public void initialize(LicenseProvider licenseProvider, Reader reader)
			throws LicenseException, IOException {
		if (!initialized) {
			if ("true".equals(OfficeGlobals
					.getLocalProperty("license.evaluation"))) {
				log
						.info("Using license information from local property (jive_startup.xml)");
				setProvider(licenseProvider);
				log
						.warn("Initialization with a license file has failed, initializing in evaluation mode.");
				setLicense(createDefaultLicense());
			} else if (reader != null) {
				log.info("Using license information from license file");
				super.initialize(licenseProvider, reader);
			} else {
				log.info("Initializing with evaluation license.");
				setLicense(createDefaultLicense());
			}
		} else {
			log.debug("Already initialized, call destroy()");
		}
	}

	public void destroy() {
		initialized = false;
	}

	public SeatStatus getSeatStatus(License license) {
		if (isInUpgrade())
			return SeatStatus.OK;
		String s = license.getLicenseData().getProperties().get(
				OfficeLicenseProperty.numSeats.name());
		if (s != null) {
			int numSeats = Integer.parseInt(s);
			if (numSeats < 1)
				return SeatStatus.OK;
			int totalUsers = 0;
			double fivePercent = (double) numSeats * 0.050000000000000003D;
			if ((double) totalUsers < (double) numSeats - fivePercent)
				return SeatStatus.OK;
			if ((double) totalUsers >= (double) numSeats - fivePercent
					&& totalUsers <= numSeats)
				return SeatStatus.WARNING;
			if (totalUsers > numSeats
					&& (double) totalUsers < (double) numSeats + fivePercent)
				return SeatStatus.EXCEEDED;
			else
				return SeatStatus.BLOCKED;
		} else {
			return SeatStatus.OK;
		}
	}

	private boolean isInUpgrade() {
		return false;
	}

	public SeatStatus getSeatStatus() {
		LicenseManager mgr = new LicenseManager();
		License license = mgr.getLicense();
		return getSeatStatus(license);
	}

	public boolean isFailed() {
		return failed;
	}

	public boolean isUnlimitedSeatLicense(License license) {
		return null == license.getLicenseData().getProperties().get(
				OfficeLicenseProperty.numSeats.name());
	}

	public String getPropertyDisplayName(String property) {
		String s = (String) propertyDisplayNames.get(property);
		if (s == null)
			s = property;
		return s;
	}

	public boolean isSeatStatusBlocked() {
		return SeatStatus.BLOCKED.equals(getSeatStatus());
	}

	public boolean isSeatStatusExceeded() {
		return SeatStatus.EXCEEDED.equals(getSeatStatus());
	}

	public boolean isSeatStatusWarning() {
		return SeatStatus.WARNING.equals(getSeatStatus());
	}

	public boolean isSeatStatusOK() {
		return SeatStatus.OK.equals(getSeatStatus());
	}

	public OfficeLicense getOfficeLicense() {
		return new OfficeLicense(getLicense());
	}

	private static LicenseData createLicenseData() {
		DefaultLicenseProvider provider = new DefaultLicenseProvider();
		LicenseData licenseData = new LicenseData();
		licenseData.setId(0L);
		licenseData.setClient(new Client("Evaluation User", "Freeborders"));
		licenseData.setType("评估版");
		Calendar calendar=new GregorianCalendar();
		licenseData.setCreateDate(calendar.getTime());
		calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR)+1);
		licenseData.setEndDate(calendar.getTime());
		licenseData.setVersion(provider.getVersion());
		licenseData.setName(provider.getName());
		String edition = OfficeGlobals.getBuildProperty("edition");
		if (edition == null)
			edition = "大众版";
		licenseData.setEdition(edition);
		licenseData.getProperties().put(OfficeLicenseProperty.numSeats.name(),
				"5");
		licenseData.getProperties().put(
				OfficeLicenseProperty.numClusterMembers.name(), "1");
		licenseData.getProperties().put("defaultLicense", "true");
		return licenseData;
	}

	public static License createDefaultLicense() {
		License defaultLicense = new License();
		defaultLicense.setLicenseData(createLicenseData());
		return defaultLicense;
	}

	public boolean isExternal() {
		License license = getLicense();
		String dev = (String) license.getLicenseData().getProperties().get(
				"developer");
		boolean isDeveloper = dev != null && "true".equalsIgnoreCase(dev);
		if (isDeveloper) {
			String s = System.getProperty("jive.license.edition");
			if (s != null) {
				if ("external".equals(s))
					return true;
				if ("internal".equals(s))
					return false;
				log.fatal((new StringBuilder()).append("Unknown edition ")
						.append(s).toString());
			}
		}
		return "external".equalsIgnoreCase(license.getLicenseData()
				.getEdition());
	}

	public static synchronized OfficeLicenseManager getInstance() {
		if (instance == null) {
			instance = new OfficeLicenseManager();
			instance.init();
		}
		return instance;
	}

	public static void main(String[] args) { 
		OfficeLicenseManager manager=OfficeLicenseManager.getInstance();
		License license=manager.getLicense();
		System.out.println(license.toXML());
	}
}
